#include "frame.h"

using namespace G3;

//==============================================================================
// Constructors and a destructor
//==============================================================================
G3::FRAME::FRAME () {
    Width = 800;
    Height = 600;
    Depth = 16;

    flags = SDL_OPENGL;

    VideoInfo = NULL;
    VideoSurface = NULL;
    Log = NULL;

    Renderer.Input = &Input;
    Renderer.MaxWidth = Width;
    Renderer.MaxHeight = Height;

    Input.Frame = this;
    Input.Mouse.SetScreenSize (Width, Height);
}

G3::FRAME::FRAME (int WindowWidth, int WindowHeight, int BitsPerPixel, int Flags) {
    Width = WindowWidth;
    Height = WindowHeight;
    Depth = BitsPerPixel;

    flags = SDL_OPENGL | Flags;

    VideoInfo = NULL;
    VideoSurface = NULL;
    Log = NULL;

    Renderer.Input = &Input;
    Renderer.MaxWidth = Width;
    Renderer.MaxHeight = Height;

    Input.Frame = this;
    Input.Mouse.SetScreenSize (Width, Height);
}

G3::FRAME::~FRAME () {
    SDL_Quit ();
}

//==============================================================================
// Creates a SDL OpenGL frame
//==============================================================================
bool G3::FRAME::Create (string Title) {
    Caption = Title;

    // Do we have a manually directed log?
    if (!Log)
        Log = &MainLog;

    // Initialize SDL
    if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
        Log->Report ("SDL_Init failed: %s\n", SDL_GetError ());
        return false;
    }

    // Query video info
    VideoInfo = SDL_GetVideoInfo ();
    if (!VideoInfo) {
        Log->Report ("SDL_GetVideoInfo failed: %s\n", SDL_GetError ());
        return false;
    }

    // Windowed mode?
    if ((flags & SDL_FULLSCREEN) == 0) {
        // We have to set up the same color depth the desktop manager uses
        Depth = VideoInfo->vfmt->BitsPerPixel;
    }

    // Doublebuffering?
//    if ((flags & SDL_DOUBLEBUF) > 0) {
        // Enable doublebuffering
        SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
/*    } else {
        // Or disable it
        SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 0);
    }*/

    if (Caption == "G3::NoWindow") {
        Uint32 rmask, gmask, bmask, amask;

        /* SDL interprets each pixel as a 32-bit number, so our masks must depend
           on the endianness (byte order) of the machine */
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
        rmask = 0xff000000;
        gmask = 0x00ff0000;
        bmask = 0x0000ff00;
        amask = 0x000000ff;
#else
        rmask = 0x000000ff;
        gmask = 0x0000ff00;
        bmask = 0x00ff0000;
        amask = 0xff000000;
#endif

        // Try to create a surface
        VideoSurface = SDL_CreateRGBSurface (flags, Width, Height, Depth, rmask, gmask, bmask, amask);

        if (!VideoSurface) {
            Log->Report ("SDL_CreateRGBSurface failed: %s\n", SDL_GetError ());
            return false;
        }
    } else {
        MainLog.Report ("Setting video mode %dx%d:%d (0x%X)..\n", Width, Height, Depth, flags);

        // Try to set video mode
        VideoSurface = SDL_SetVideoMode (Width, Height, Depth, flags | SDL_HWSURFACE);

        MainLog.Report ("Surface: 0x%X\n", VideoSurface);

        if (!VideoSurface) {
            Log->Report ("SDL_SetVideoMode failed: %s\n", SDL_GetError ());
            return false;
        }
    }

    if (Caption != "G3::NoWindow") {
        // Set frame title
        SDL_WM_SetCaption (Caption.c_str (), NULL);
    }

    return true;
}

//==============================================================================
// The same, but with arguments
//==============================================================================
bool G3::FRAME::Create (string Title, int WindowWidth, int WindowHeight, int BitsPerPixel, int Flags) {
    Width = WindowWidth;
    Height = WindowHeight;
    Depth = BitsPerPixel;

    flags |= Flags;

    Renderer.Input = &Input;
    Renderer.MaxWidth = Width;
    Renderer.MaxHeight = Height;

    Input.Frame = this;
    Input.Mouse.SetScreenSize (Width, Height);

    return Create (Title);
}

//==============================================================================
// Just a default input update handler function that programmer can override
//==============================================================================
void G3::DefaultUpdateHandler (INPUT *Input, float aElapsedTime) {
	if (Input->Keyboard.IsKeyDown (SDLK_a))
		Input->Frame->Renderer.Camera.Move (VEC3F (0.0f, 1.0f, 0.0f) * aElapsedTime);
	if (Input->Keyboard.IsKeyDown (SDLK_z))
		Input->Frame->Renderer.Camera.Move (VEC3F (0.0f, -1.0f, 0.0f) * aElapsedTime);
	if (Input->Keyboard.IsKeyDown (SDLK_LEFT))
		Input->Frame->Renderer.Camera.Move (VEC3F (-1.0f, 0.0f, 0.0f) * aElapsedTime);
	if (Input->Keyboard.IsKeyDown (SDLK_RIGHT))
		Input->Frame->Renderer.Camera.Move (VEC3F (1.0f, 0.0f, 0.0f) * aElapsedTime);
	if (Input->Keyboard.IsKeyDown (SDLK_UP))
		Input->Frame->Renderer.Camera.Move (VEC3F (0.0f, 0.0f, 1.0f) * aElapsedTime);
	if (Input->Keyboard.IsKeyDown (SDLK_DOWN))
		Input->Frame->Renderer.Camera.Move (VEC3F (0.0f, 0.0f,-1.0f) * aElapsedTime);

	if (Input->Keyboard.IsKeyDown (SDLK_ESCAPE))
		Input->SendQuit ();
}
